package gui;

import java.util.ArrayList;
import java.util.List;

import logic.ChessGame;
import logic.IPlayerHandler;
import logic.Log;
import logic.Move;
import logic.MoveValidator;
import logic.Piece;

public class SimpleAIHandler implements IPlayerHandler {

	private ChessGame chessGame;
	private MoveValidator validator;
	public int depth = 2;

	public SimpleAIHandler(ChessGame chessGame) {
		this.chessGame = chessGame;
		this.validator = this.chessGame.getMoveValidator();

	}

	@Override
	public Move getMove() {
		return getBestMove();

	}

	@Override
	public void moveSuccessfullyExecuted(Move move) {
		System.out.println("executed: " + move);
	}

	private Move getBestMove() {
		System.out.println("thinking");
		Log.getInstance().log("logai|thinking...");
		List<Move> validMoves = generateMoves();
		int bestResult = Integer.MIN_VALUE;
		Move bestMove = null;
		int alpha = Integer.MIN_VALUE;
		int beta = Integer.MAX_VALUE;
		for (Move move : validMoves) {
			executeMove(move);
			int evaluationResult = -negaMax(this.depth, alpha, beta);
			// System.out.println(evaluationResult);
			undoMove(move);
			if (evaluationResult > bestResult) {
				// System.out.println("find");
				bestResult = evaluationResult;
				bestMove = move;
			}
		}

		// System.out.println("best move is..." + bestMove);
		return bestMove;
	}

	private int negaMax(int depth, int alpha, int beta) {
		if (depth <= 0
				|| this.chessGame.getGameState() == ChessGame.GAME_STATE_END_GREEN_WON
				|| this.chessGame.getGameState() == ChessGame.GAME_STATE_END_RED_WON) {
			return evaluateState();
		}

		List<Move> moves = this.generateMoves();
		int currentMax = Integer.MIN_VALUE;
		// int count = 0;
		for (Move currentMove : moves) {
			// System.out.println(count + "move to: " + currentMove);
			// System.out.println(count
			// + "move: "
			// + chessGame.getNonCapturedPieceAtLocation(
			// currentMove.getSourceRow(),
			// currentMove.getSourceColumn()));
			executeMove(currentMove);
			int score = -1 * negaMax(depth - 1, -beta, -alpha);
			// System.out.println(count
			// + "undo move: "
			// + chessGame.getNonCapturedPieceAtLocation(
			// currentMove.getTargetRow(),
			// currentMove.getTargetColumn()));
			undoMove(currentMove);
			// System.out.println(score);
			if (score > currentMax) {

				currentMax = score;
			}
			// count++;
			alpha = Math.max(alpha, score);
			if (alpha >= beta)
				break;

		}
		// System.out.println(currentMax);
		return currentMax;
	}

	private void undoMove(Move move) {
		this.chessGame.undoMove(move);
		// this.chessGame.changeGameState();
	}

	private int evaluateState() {
		// add up score

		int scoreRed = 0;
		int scoreGreen = 0;
		for (Piece piece : chessGame.getPieces()) {
			if (piece.getColor() == Piece.COLOR_GREEN) {
				scoreGreen += getScoreForPieceType(piece.getType());

			} else if (piece.getColor() == Piece.COLOR_RED) {
				scoreRed += getScoreForPieceType(piece.getType());
			} else {
				throw new IllegalStateException("unknown piece color found: "
						+ piece.getColor());
			}
		}
		// return evaluation result depending on who's turn it is
		int gameState = this.chessGame.getGameState();
		if (gameState == ChessGame.GAME_STATE_GREEN) {
			return scoreGreen - scoreRed;
		} else if (gameState == ChessGame.GAME_STATE_RED) {
			return scoreRed - scoreGreen;
		} else if (gameState == ChessGame.GAME_STATE_END_GREEN_WON
				|| gameState == ChessGame.GAME_STATE_END_RED_WON) {
			return Integer.MIN_VALUE + 1;
		} else {
			throw new IllegalStateException("unknows game state: " + gameState);
		}
	}

	private int getScoreForPieceType(int type) {
		switch (type) {
		case Piece.TYPE_CANNON:
			return 50;
		case Piece.TYPE_ELEPHANT:
			return 10;
		case Piece.TYPE_GUARD:
			return 20;
		case Piece.TYPE_KING:
			return 200;
		case Piece.TYPE_HOURSE:
			return 30;
		case Piece.TYPE_PAWN:
			return 5;
		case Piece.TYPE_ROOK:
			return 80;
		default:
			throw new IllegalArgumentException("unknown piece type: " + type);
		}
	}

	private void executeMove(Move move) {

		this.chessGame.movePiece(move);
		this.chessGame.changeGameState();
		// if (moved) {
		// this.chessGame.changeGameState();
		// }
		// return moved;
	}

	private List<Move> generateMoves() {
		List<Move> validMoves = new ArrayList<Move>();
		Move testMove = new Move(0, 0, 0, 0);

		int pieceColor = (this.chessGame.getGameState() == ChessGame.GAME_STATE_GREEN) ? Piece.COLOR_GREEN
				: Piece.COLOR_RED;

		for (Piece piece : this.chessGame.getPieces()) {
			if (pieceColor == piece.getColor()) {
				// start generating move
				testMove.setSourceRow(piece.getRow());
				testMove.setSourceColumn(piece.getColumn());

				// iterate over all board rows and columns
				for (int targetRow = Piece.ROW_1; targetRow <= Piece.ROW_10; targetRow++) {
					for (int targetColumn = Piece.COLUMN_A; targetColumn <= Piece.COLUMN_I; targetColumn++) {
						// finish generating move
						testMove.setTargetRow(targetRow);
						testMove.setTargetColumn(targetColumn);

						// check if generated move is valid
						if (this.validator.isMoveValid(testMove, false)) {
							// valid move
							validMoves.add(testMove.clone());
						}
					}
				}
			}
		}
		return validMoves;
	}
}
